﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.Windows.Threading;
namespace SockLib
{
   public    class SocketServer
    {
        #region 服务器操作

       /// <summary>
       /// 监听Socket
       /// </summary>
       public  Socket listenSocket;

       /// <summary>
       /// SocketAsyncEventArgs池
       /// </summary>
     public   SocketEventPool  SocketAsyncPool ;


        public Logs.WriteLog  PrintLog;

       /// <summary>
       /// 最大连入客户端
       /// </summary>
        Semaphore MaxAcceptedClients;

       /// <summary>
       /// 服务器是否在运行
       /// </summary>
       Boolean  ServerIsRun;


       IPEndPoint localEndPoint;

       /// <summary>
       /// 开始一个服务
       /// </summary>
       /// <param name="port">服务端口号</param>
       /// <param name="capacity">允许连入设备数量</param>
       /// <param name="ServerIP">连接成功返回服务器IP和端口号</param>
       /// <returns>true：开启成功，flase：开启失败或已经运行</returns>
        public Boolean  StartServer(int port,int capacity,IPAddress IP, out  string ServerIP,SocketEventPool.RegSocketModify RSM )
        {
            try
            {
                if (ServerIsRun)
                {
                    ServerIP = "正在运行";
                    return false ;
                }
                ServerIsRun = true;
                localEndPoint = new IPEndPoint(IP, port);
                ServerIP = localEndPoint.Address.ToString() + ":" + localEndPoint.Port.ToString();
                listenSocket = new Socket(localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                listenSocket.Bind(localEndPoint);
                listenSocket.Listen(0);  //不允许等待队列
                listenSocket.LingerState.Enabled = false;
                SocketModel.CloseClient SCC = new SocketModel.CloseClient(CloseClientSocket);
                SocketAsyncPool = new SocketEventPool(capacity, SCC, RSM, PrintLog);
                MaxAcceptedClients = new Semaphore(capacity, capacity);
                ports = port;
                StartAccept(null);
                return true;
            }
            catch (Exception ex)
            {
                logexception.WriteLogToFile(ex);
                ServerIP = "连接失败---" + ex.ToString();
                ServerIsRun = false;
                return false;
            }
        }


        internal static int ports;

        /// <summary>
        /// 获取IPV4地址
        /// </summary>
        /// <returns></returns>
        List<IPAddress> GetLocalIpv4()  
         {  
            IPAddress[] localIPs;  
             localIPs = Dns.GetHostAddresses(Dns.GetHostName());
             List<IPAddress> IPV4 = new List<IPAddress>();
             foreach (IPAddress ip in localIPs)  
             {  
                 //根据AddressFamily判断是否为ipv4,如果是InterNetWorkV6则为ipv6  
                 if (ip.AddressFamily == AddressFamily.InterNetwork)
                     IPV4.Add(ip);  
             }
             return IPV4;  
         } 


     /// <summary>
     /// 关闭服务
     /// </summary>
        public void  StopServer()
        {
            if (ServerIsRun==false )
                return  ;
            ServerIsRun = false;
            listenSocket.Close();
            listenSocket.Dispose();
            SocketAsyncPool.DisPoseSocketPool();
            SocketAsyncPool.SocketPool.Clear();
            for (int i = SocketAsyncPool.NoRegSocket.Count - 1; i >= 0; i--)   //关闭在线已注册
            {
                SocketModel SM = SocketAsyncPool.NoRegSocket[i];
                try
                {
                    if(SM.ReceiveSAEA.AcceptSocket.Connected )
                    SM.ReceiveSAEA.AcceptSocket .Shutdown(SocketShutdown.Both );
                    
                }
                catch (Exception ex)
                {
                    logexception.WriteLogToFile(ex);
                }
                SM.ReceiveSAEA.AcceptSocket .Close();
            }
            for (int i = SocketAsyncPool.RegSocket .Count  - 1; i >= 0; i--)  //关闭未注册
            {
                SocketModel SM = SocketAsyncPool.RegSocket[i];
                try
                {
                    if(SM.ReceiveSAEA.AcceptSocket.Connected )
                    SM.ReceiveSAEA.AcceptSocket .Shutdown(SocketShutdown.Both);
                }
                catch (Exception ex)
                {
                    logexception.WriteLogToFile(ex);
                }
                SM.ReceiveSAEA.AcceptSocket .Close();
            }
        }

        /// <summary>
        /// 开始一个异步监听Socket连入
        /// </summary>
        /// <param name="acceptEventArg"></param>
        void StartAccept(SocketAsyncEventArgs acceptEventArg)
        {
            MaxAcceptedClients.WaitOne();
            if (acceptEventArg == null)
            {
                acceptEventArg = new SocketAsyncEventArgs();
                acceptEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(acceptEventArg_Completed);
            }
            else
            {
                acceptEventArg.AcceptSocket = null;
            }
            if (ServerIsRun == false)
                return;
            bool willRaiseEvent = listenSocket.AcceptAsync(acceptEventArg);
                
            if (!willRaiseEvent)
            {
                ProcessAccept(acceptEventArg);
            }        
        }


       /// <summary>
       /// 监听到一个客户端连入
       /// </summary>
       /// <param name="sender"></param>
       /// <param name="e"></param>
        void acceptEventArg_Completed(object sender, SocketAsyncEventArgs e)
        {
            if (e.LastOperation != SocketAsyncOperation.Accept)
                return;
            if (ServerIsRun == false)   //服务器需要停止的话退出异步监听
                return;
            ProcessAccept(e);
        }


       /// <summary>
       /// 初始化连入客户端
       /// </summary>
       /// <param name="e"></param>
        void ProcessAccept(SocketAsyncEventArgs e)
        {
            try
            {
                SocketModel SAEA = SocketAsyncPool.Pop();  //取一个实例出来使用
                SAEA.SaveSocket(e.AcceptSocket);
                IPEndPoint IPS = (IPEndPoint)e.AcceptSocket.RemoteEndPoint;
                string print = string.Format("{0}--客户端连入{1}", DateTime.Now, IPS.ToString());
                Console.WriteLine(print);
                PrintLog("", "", 0, print);
                SocketAsyncPool.NoRegSocket.Add(SAEA);
                bool willRaiseEvent = e.AcceptSocket.ReceiveAsync(SAEA.ReceiveSAEA);
                if (!willRaiseEvent)
                {
                    SAEA.ProcessReceive(SAEA.ReceiveSAEA);
                }
                StartAccept(e);
            }
            catch (Exception ex)
            {
                StartAccept(e);
                logexception.WriteLogToFile(ex);
            }
        
        }

        /// <summary>
        /// 关闭客户端
        /// </summary>
        /// <param name="S"></param>
        void CloseClientSocket(SocketModel S)
        {
            lock (SocketAsyncPool.LockThis)
            {
                if (SocketAsyncPool.NoRegSocket.Contains(S))
                    SocketAsyncPool.NoRegSocket.Remove(S);
                if (SocketAsyncPool.RegSocket.Contains(S))
                    SocketAsyncPool.RegSocket.Remove(S);
                S.Uid = "-1";       //表示此设备未被初始化不可用
                SocketAsyncPool.Push(S);    //放回池内重新使用
                MaxAcceptedClients.Release();
            }
        }


        public int getcount()
        {
            return SocketAsyncPool.ConnectDeviceNum;
        }
        #endregion


    }
}
